﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.Reflection;
using System.Xml;
using VNet.VisiSuite.Common.Logger;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.IO;
using VNet.VisiSuite.VisiBoard.Common;
using Microsoft.Win32;
using VNet.VisiSuite.Common.Helper;
using VNet.VisiSuite.Common;
using VNet.VisiSuite.Service.Proxy;
using VNet.VisiSuite.Service.Contact.Message.Base;
using System.Drawing;

using Infragistics.Themes;

namespace VNet.VisiSuite.VisiBoard
{
    public partial class App : Application
    {
        private Mutex _mutex;
        private static string _application_name = null;
        private static Version _application_version = null;

        public static Version PublishedVersion()
        {
            if (_application_version == null)
            {
                XmlDocument xmlDoc = new XmlDocument();
                Assembly asmCurrent = System.Reflection.Assembly.GetExecutingAssembly();
                string executePath = new Uri(asmCurrent.GetName().CodeBase).LocalPath;

                xmlDoc.Load(executePath + ".manifest");
                string retval = string.Empty;
                if (xmlDoc.HasChildNodes)
                {
                    retval = xmlDoc.ChildNodes[1].ChildNodes[0].Attributes.GetNamedItem("version").Value.ToString();
                }
                _application_version = new Version(retval);
            }
            return _application_version;
        }

        public static void setStartup()
        {
#if !DEBUG
            // The path to the key where Windows looks for startup applications
            RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);

            //Path to launch shortcut
            Assembly asmCurrent = System.Reflection.Assembly.GetExecutingAssembly();
            string executePath = new Uri(asmCurrent.GetName().CodeBase).LocalPath;
            rk.SetValue("VisiBoard", executePath);
#endif
        }

        public static string ApplicationName()
        {
            if (_application_name == null)
            {
                AssemblyProductAttribute product = (AssemblyProductAttribute)AssemblyProductAttribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyProductAttribute));
                _application_name = product.Product;
            }
            return _application_name;
        }

        public static string ApplicationNameAndVersion()
        {
            return string.Format("{0} v{1}", ApplicationName(), PublishedVersion().ToString());
        }

        protected override void OnStartup(StartupEventArgs theArgs)
        {
            base.OnStartup(theArgs);

            bool new_instance = false;
            _mutex = new Mutex(true, ApplicationName(), out new_instance);  //Creates a mutex for the application

            if (!new_instance)
            {
                FocusApp();
                Application.Current.Shutdown();  //Shutdown when a new mutex with the same name is created
            }
            else
            {
                Version ver = PublishedVersion();
                string msg = ApplicationName() + " " + ver.ToString() + " started.";
                FileLog.Info(msg);
                setStartup();
            }

            // Log all unhandled exceptions.
            this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnCurrentDomainUnhandledException);

            ThemeManager.ApplicationTheme = new MetroTheme() { StyleMicrosoftControls = true };

            SetDataDirectory();
            verifyDatabase();

            // Update the database if need ve
            var version_util = new VNet.VisiSuite.VisiBoard.BusinessLogic.VersionUtil();
            version_util.CheckExistingData();

            if (version_util.CompareDBVersion("2.0.2", version_util.GetDBVersion()) > 0)
                SetDataDirectory(true);   

            version_util = null;

            VNet.VisiSuite.VisiBoard.WebServer.SystemInfo.version(PublishedVersion().ToString());

            DownloadLogoImage();
        }

        private static void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            try
            {
                FileLog.Fatal("Unhandled exception: ", e.Exception);
            }
            catch
            {
                // to prevent recursion.
            }
        }

        static private void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            try
            {
                Exception ex = (Exception)e.ExceptionObject;
                FileLog.Fatal("Unhandled domain exception: ", ex);
            }
            catch
            {
                // to prevent recursion.
            }
        }

        [DllImport("user32.dll")]
        public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr WindowHandle);
        public const int SW_RESTORE = 9;

        private bool FocusApp()
        {
            Process[] processes = Process.GetProcessesByName(ApplicationName());
            if (processes.Length > 0)
            {
                IntPtr hwnd = IntPtr.Zero;
                hwnd = processes[0].MainWindowHandle;
                ShowWindowAsync(new HandleRef(null, hwnd), SW_RESTORE);
                SetForegroundWindow(hwnd);
                return true;
            }
            return false;
        }

        private void SetDataDirectory(bool force_overwrite = false)
        {
            RegistryKey reg = RegistryHelper.OpenRegistryVisi(CommonConstants.RegistryVisiSuite, true);  // creates or opens in write mode.
            try
            {
                string path = (string)reg.GetValue(Constants.RegistryDataDir);

                if (string.IsNullOrEmpty(path))
                {
                    try
                    {
                        // Use the default location
                        path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); // c:\ProgramData 
                        path = string.Format("{0}\\{1}\\{2}", path, CommonConstants.RegistryLeanlogic, CommonConstants.RegistryVisiSuite);
                        reg.SetValue(Constants.RegistryDataDir, path);
                    }
                    catch (Exception ex)
                    {
                        FileLog.Error("Error writing data directory to registry.", ex);
                    }
                }

                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                // Copy a blank database to this location if need be
                string dbPath = Path.Combine(path, Constants.VisiBoardSdfFile);
                if (!File.Exists(dbPath) || force_overwrite)
                {
                    string fromPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), Constants.VisiBoardSdfFile);
                    File.Delete(dbPath);
                    File.Copy(fromPath, dbPath);
                }

                reg.Close();

                // Set |DataDirectory| value used by data access layer.
                AppDomain.CurrentDomain.SetData("DataDirectory", path);

            }
            catch (Exception ex)
            {
                FileLog.Fatal("Fatal error setting data directory: ", ex);
            }
            finally
            {
                reg.Close();
            }
        }

        private bool verifyDatabase()
        {

            string connection = System.Configuration.ConfigurationManager.AppSettings["ConnectionString.SQL Server (SqlClient)"];

            System.Data.SqlServerCe.SqlCeEngine engine = new System.Data.SqlServerCe.SqlCeEngine(connection);
            if (engine.Verify() == false)
            {
                FileLog.Warn("Repairing database.");
                engine.Repair(null, System.Data.SqlServerCe.RepairOption.RecoverAllOrFail);

                if (engine.Verify() == false)
                    throw new Exception("Database file is corrupt.");
            }

            engine.Shrink();
            engine.Compact(connection);

            engine.Dispose();
            engine = null;

            return true;
        }

        public static void DownloadLogoImage()
        {
            try
            {
                if (RegistryHelper.CheckRegistryInstallKeyExist())
                {
                    using (var client = new VNetVisiSuiteSecurityContractClient())
                    {
                        var reg = RegistryHelper.OpenRegistryVisi(CommonConstants.RegistryVisiSuite, false);
                        var request = new GetDataRequest { DataDescription = reg.GetValue(CommonConstants.RegistryInstallKey).ToString() };
                        reg.Close();

                        var response = client.DownloadLogoImage(request);

                        if (!response.Success || response.Data == null)
                            return;

                        //FileLog.Error("DownloadLogoImage() - Image" + (response.Data.Image == null ? "null" : "okay"));

                        Bitmap bitmapImage = response.Data != null ? (Bitmap)ImageHelper.ConvertByteArrayToImage(response.Data.Image) : null;
                        var localFilePath = FileHelper.Resolution(bitmapImage, FileHelper.GetExtension(response.Data.FileName), response.Data.FileName);
                        Constants.StaticData.LogoPath = localFilePath;
                    }
                }
            }
            catch (Exception ex)
            {
                FileLog.Error("DownloadLogoImage() - ", ex);
            }
        }
    }
}